package com.atguigu.juc.locksupport;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Description: 等待唤醒机制
 * @author： yeswater
 * @create： 2024/5/30
 */

public class LockSupportDemo {
	
	public static void main(String[] args) {
		//m1_wait_notify();
		//m1_wait_notify2();
		//m1_wait_notify3();
		
		//m2_await_signal();
		//m2_await_signal2();
		//m2_await_signal3();
		
		m3_park_unpark();
	}
	
	/* park() + unpark() 实现等待唤醒 不需要同步代码快 不在乎顺序 */
	private static void m3_park_unpark() {
		Thread t1 = new Thread(() -> {
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
			System.out.println(Thread.currentThread().getName() + " start");
			System.out.println(Thread.currentThread().getName() + " park");
			LockSupport.park();
			System.out.println(Thread.currentThread().getName() + " continue");
		}, "t1");
		t1.start();
		
		//try {
		//	TimeUnit.SECONDS.sleep(1);
		//} catch (InterruptedException e) {
		//	throw new RuntimeException(e);
		//}
		
		new Thread(() -> {
			System.out.println(Thread.currentThread().getName() + " unpark");
			LockSupport.unpark(t1);
		},"t2").start();
	}
	
	/* lock + await + signal 实现等待唤醒 */
	private static void m2_await_signal() {
		ReentrantLock lock = new ReentrantLock();
		Condition condition = lock.newCondition();
		
		new Thread(() -> {
			System.out.println(Thread.currentThread().getName() + " come in");
			try {
				lock.lock();
				System.out.println(Thread.currentThread().getName() + " await");
				condition.await();
				System.out.println(Thread.currentThread().getName() + " is notified");
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			} finally {
				lock.unlock();
			}
		}, "t1").start();
		
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
		
		new Thread(() -> {
			System.out.println(Thread.currentThread().getName() + " come in");
			try {
				lock.lock();
				condition.signal();
				System.out.println(Thread.currentThread().getName() + " signal");
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}, "t2").start();
	}
	
	/* lock + await + signal 必须结合lock.lock 同步代码块 */
	private static void m2_await_signal2() {
		ReentrantLock lock = new ReentrantLock();
		Condition condition = lock.newCondition();
		
		new Thread(() -> {
			System.out.println(Thread.currentThread().getName() + " come in");
			try {
				//lock.lock();
				System.out.println(Thread.currentThread().getName() + " await");
				condition.await();
				System.out.println(Thread.currentThread().getName() + " is notified");
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			} finally {
				//lock.unlock();
			}
		}, "t1").start();
		
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
		
		new Thread(() -> {
			System.out.println(Thread.currentThread().getName() + " come in");
			try {
				//lock.lock();
				condition.signal();
				System.out.println(Thread.currentThread().getName() + " signal");
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				//lock.unlock();
			}
		}, "t2").start();
	}
	
	/* lock + await + signal 必须先await  后signal 才能唤醒 */
	private static void m2_await_signal3() {
		ReentrantLock lock = new ReentrantLock();
		Condition condition = lock.newCondition();
		
		new Thread(() -> {
			try {
				TimeUnit.SECONDS.sleep(2);
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
			System.out.println(Thread.currentThread().getName() + " come in");
			try {
				lock.lock();
				System.out.println(Thread.currentThread().getName() + " await");
				condition.await();
				System.out.println(Thread.currentThread().getName() + " is notified");
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			} finally {
				lock.unlock();
			}
		}, "t1").start();
		
		
		
		new Thread(() -> {
			System.out.println(Thread.currentThread().getName() + " come in");
			try {
				lock.lock();
				condition.signal();
				System.out.println(Thread.currentThread().getName() + " signal");
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}, "t2").start();
	}
	
	/* synchronized + object 的 wait 和 notify 实现等待唤醒 */
	private static void m1_wait_notify() {
		Object objLock = new Object();
		
		new Thread(() -> {
			synchronized (objLock) {
				System.out.println(Thread.currentThread().getName() + " start");
				try {
					objLock.wait();
					System.out.println(Thread.currentThread().getName() + " wait");
				} catch (InterruptedException e) {
					throw new RuntimeException(e);
				}
				System.out.println(Thread.currentThread().getName() + " is notified");
			}
		}, "t1").start();
		
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
		
		new Thread(() -> {
			synchronized (objLock) {
				objLock.notify();
				System.out.println(Thread.currentThread().getName() + " do notify");
			}
		}, "t2").start();
	}
	
	/* 异常情况: notify() 先执行 ，程序无法唤醒 */
	private static void m1_wait_notify2() {
		Object objLock = new Object();
		
		new Thread(() -> {
			try {
				TimeUnit.SECONDS.sleep(2);
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
			
			synchronized (objLock) {
				System.out.println(Thread.currentThread().getName() + " start");
				try {
					objLock.wait();
					System.out.println(Thread.currentThread().getName() + " wait");
				} catch (InterruptedException e) {
					throw new RuntimeException(e);
				}
				System.out.println(Thread.currentThread().getName() + " is notified");
			}
		}, "t1").start();
		
		
		new Thread(() -> {
			synchronized (objLock) {
				objLock.notify();
				System.out.println(Thread.currentThread().getName() + " do notify");
			}
		}, "t2").start();
	}
	
	
	/**
	 * 异常情况: notify() 和 wait() 必须放在同步代码块中 否则报错
	 * <p>
	 * Exception in thread "t2" java.lang.IllegalMonitorStateException
	 * at java.lang.Object.notify(Native Method)
	 * at com.atguigu.juc.locksupport.LockSupportDemo.lambda$m1_wait_notify3$5(LockSupportDemo.java:110)
	 * at java.lang.Thread.run(Thread.java:748)
	 * t1 start
	 * Exception in thread "t1" java.lang.IllegalMonitorStateException
	 * at java.lang.Object.wait(Native Method)
	 * at java.lang.Object.wait(Object.java:502)
	 * at com.atguigu.juc.locksupport.LockSupportDemo.lambda$m1_wait_notify3$4(LockSupportDemo.java:97)
	 * at java.lang.Thread.run(Thread.java:748)
	 */
	private static void m1_wait_notify3() {
		Object objLock = new Object();
		
		new Thread(() -> {
			try {
				TimeUnit.SECONDS.sleep(2);
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
			
			//synchronized (objLock) {
			System.out.println(Thread.currentThread().getName() + " start");
			try {
				objLock.wait();
				System.out.println(Thread.currentThread().getName() + " wait");
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
			System.out.println(Thread.currentThread().getName() + " is notified");
			//}
		}, "t1").start();
		
		
		new Thread(() -> {
			//synchronized (objLock) {
			objLock.notify();
			System.out.println(Thread.currentThread().getName() + " do notify");
			//}
		}, "t2").start();
	}
	
}
